#!/usr/bin/perl

package Swignition::Export::Feed;

use Swignition::Export;
use Swignition::Export::BlogEntry;
use Swignition::MagicString;
use Swignition::uF;
use HTML::Entities qw(encode_entities_numeric);
use DateTime;

sub is
{
	my $subject = shift;
	return unless (ref $subject eq 'Swignition::RDFModel::Subject');	
	return
		unless (defined $subject->property('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'));
	foreach my $Type ( @{$subject
		->property('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')
		->valObjects} )
	{
		my $type = $Type->toString;
		return 1
			if (($type eq 'http://purl.org/rss/1.0/channel')
			||  ($type eq 'http://purl.invalid/stuff/atom/owl#Feed')
			||  ($type eq 'http://bblfish.net/work/atom-owl/2006-06-06/#Feed')
			);			
	}
	
	return 1 if (firstOf($subject,
		'http://purl.org/rss/1.0/items',
		'http://purl.invalid/stuff/atom/owl#entry',
		'http://bblfish.net/work/atom-owl/2006-06-06/#entry'
		));
	
	return;
}

sub outputs
{
	return [
		{
			code  => 'Atom',
			name  => 'Atom Feed',
			type  => 'application/atom+xml',
			multi => 1
		}
	];
}

sub AtomDate
{
	my $dt = shift;

	return undef unless $dt;
	
	$dt = Swignition::uF::datetime($dt)
		unless (ref $dt eq 'DateTime');
	
	$dt = "$dt";
	$dt =~ s/([\+\-])(\d\d)(\d\d)$/$1$2:$3/;

	return $dt;
}

sub AtomOwlContent
{
	my $subject = shift;
	return undef unless ($subject);
	
	my $isAtomOwlContent = 0;
	
	# If has rdf:type of awol:Content, set $isAtomOwlContent to 1.
	my @types = allOf($subject, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
	foreach my $type (@types)
	{
		if ($type eq 'http://bblfish.net/work/atom-owl/2006-06-06/#Content'
		||  $type eq 'http://purl.invalid/stuff/atom/owl#Content')
		{
			$isAtomOwlContent = 1;
			last;
		}
	}
	
	# If has an awol:body property, set $isAtomOwlContent to 1.
	my $body = firstOf($subject,
		'http://purl.invalid/stuff/atom/owl#body',
		'http://bblfish.net/work/atom-owl/2006-06-06/#body');
	$isAtomOwlContent = 1 if ($body);
	
	return undef unless $isAtomOwlContent;
	
	my $type = firstOf($subject,
		'http://purl.invalid/stuff/atom/owl#type',
		'http://bblfish.net/work/atom-owl/2006-06-06/#type');

	return [$type, $body];
}

sub multiAtom
{
	my $triples = shift;
	my $rv = '';
	foreach my $s (keys %$triples)
	{
		$rv .= outAtom($triples, $s) . "\n\n"
			if (defined $triples->{$s} && is($triples->{$s}));
	}
	return $rv;
}

sub outAtom
{
	my $triples = shift;
	my $subject = shift;
	my $S = $triples->{$subject};
	my $rv = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
	$rv .= "<feed xmlns=\"http://www.w3.org/2005/Atom\"\n";
	$rv .= "      xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n";
	$rv .= "      xmlns:thr=\"http://purl.org/syndication/thread/1.0\">\n";
	$rv .= "\t<generator>swignition</generator>\n";
	
	my $link = firstOf($S,
		'http://www.iana.org/assignments/relation/self',
		'http://purl.org/rss/1.0/link',
		'http://www.w3.org/2006/link#uri');
	$link = $e unless length $link;
	my $id = firstOf($S,
		'http://purl.invalid/stuff/atom/owl#id',
		'http://bblfish.net/work/atom-owl/2006-06-06/#id',
		'http://www.w3.org/2002/12/cal/ical#uid',
		'http://purl.org/dc/terms/identifier',
		'http://purl.org/dc/elements/1.1/identifier');
	$id = $link unless length $id;
	$rv .= "\t<id>".encode_entities_numeric($id)."</id>\n" if ($id);
	$rv .= "\t<link rel=\"alternate\" href=\"".encode_entities_numeric($link)."\" />\n"
		if ($link && ($link !~ m|^bnode:///|));

	my @contents = allOfObj($S,
		'http://purl.invalid/stuff/atom/owl#title',
		'http://bblfish.net/work/atom-owl/2006-06-06/#title',
		'http://purl.org/rss/1.0/title',
		'http://purl.org/dc/terms/title',
		'http://purl.org/dc/elements/1.1/title',
		'http://www.w3.org/2000/01/rdf-schema#label');
	my $cnt;
	my $cnt_type;
	if (@contents)
	{
		foreach my $c (@contents)
		{
			if ($c->type)
			{
				my $C = findSubject($triples, $c->toString);
				my $content = AtomOwlContent($C);
				if ($content)
				{
					$cnt_type = $content->[0];
					$cnt      = $content->[1];
					last;
				}
			}
			else
			{
				$cnt_type = 'text/plain';
				$cnt      = $c->toString;
				last;
			}
		}
	}
	if ($cnt)
	{
		$cnt_type = 'html'
			if ($cnt_type =~ m#^(text/html|application/xhtml+xml|application/vnd.wap.xhtml+xml)$#i);
		$cnt_type = 'text'
			if ($cnt_type =~ m#^(text/plain)$#);
	
		if (isms($cnt))
		{
			$rv .= sprintf("\t<title xml:lang=\"%s\" type=\"%s\">%s</title>\n",
				encode_entities_numeric($cnt->{lang}),
				encode_entities_numeric($cnt_type),
				encode_entities_numeric("$cnt"));
		}
		else
		{
			$rv .= sprintf("\t<title type=\"%s\">%s</title>\n",
				encode_entities_numeric($cnt_type),
				encode_entities_numeric($cnt));
		}
	}
	else
	{
		$rv .= "\t<title xml:lang=\"en\">Untitled</title>\n";
	}
	
	my @contents = allOfObj($S,
		'http://purl.invalid/stuff/atom/owl#subtitle',
		'http://bblfish.net/work/atom-owl/2006-06-06/#subtitle',
		'http://purl.org/dc/terms/abstract');
	my $cnt;
	my $cnt_type;
	if (@contents)
	{
		foreach my $c (@contents)
		{
			if ($c->type)
			{
				my $C = findSubject($triples, $c->toString);
				my $content = AtomOwlContent($C);
				if ($content)
				{
					$cnt_type = $content->[0];
					$cnt      = $content->[1];
					last;
				}
			}
			else
			{
				$cnt_type = 'text/plain';
				$cnt      = $c->toString;
				last;
			}
		}
	}
	if ($cnt)
	{
		$cnt_type = 'html'
			if ($cnt_type =~ m#^(text/html|application/xhtml+xml|application/vnd.wap.xhtml+xml)$#i);
		$cnt_type = 'text'
			if ($cnt_type =~ m#^(text/plain)$#);
	
		if (isms($cnt))
		{
			$rv .= sprintf("\t<subtitle xml:lang=\"%s\" type=\"%s\">%s</subtitle>\n",
				encode_entities_numeric($cnt->{lang}),
				encode_entities_numeric($cnt_type),
				encode_entities_numeric("$cnt"));
		}
		else
		{
			$rv .= sprintf("\t<subtitle type=\"%s\">%s</subtitle>\n",
				encode_entities_numeric($cnt_type),
				encode_entities_numeric($cnt));
		}
	}

	my @contents = allOfObj($S,
		'http://purl.org/rss/1.0/description',
		'http://purl.org/dc/terms/description',
		'http://purl.org/dc/elements/1.1/description');
	my $cnt;
	my $cnt_type;
	if (@contents)
	{
		foreach my $c (@contents)
		{
			if ($c->type)
			{
				my $C = findSubject($triples, $c->toString);
				my $content = AtomOwlContent($C);
				if ($content)
				{
					$cnt_type = $content->[0];
					$cnt      = $content->[1];
					last;
				}
			}
			else
			{
				$cnt_type = 'text/plain';
				$cnt      = $c->toString;
				last;
			}
		}
	}
	if ($cnt)
	{
		$cnt_type = 'html'
			if ($cnt_type =~ m#^(text/html|application/xhtml+xml|application/vnd.wap.xhtml+xml)$#i);
		$cnt_type = 'text'
			if ($cnt_type =~ m#^(text/plain)$#);
	
		if (isms($cnt))
		{
			$rv .= sprintf("\t<dc:description xml:lang=\"%s\" type=\"%s\">%s</dc:description>\n",
				encode_entities_numeric($cnt->{lang}),
				encode_entities_numeric($cnt_type),
				encode_entities_numeric("$cnt"));
		}
		else
		{
			$rv .= sprintf("\t<dc:description type=\"%s\">%s</dc:description>\n",
				encode_entities_numeric($cnt_type),
				encode_entities_numeric($cnt));
		}
	}
	
	my @authors = allOfObj($E,
		'http://purl.invalid/stuff/atom/owl#author',
		'http://bblfish.net/work/atom-owl/2006-06-06/#author',
		'http://purl.org/dc/terms/creator',
		'http://purl.org/dc/elements/1.1/creator',
		'http://xmlns.com/foaf/0.1/maker',
		'http://www.w3.org/2002/12/cal/ical#organizer');
	foreach my $author (@authors)
	{
		my $authorSubject = findSubject($triples, $author->toString);
		if ($authorSubject && Swignition::Export::Contact::is($authorSubject))
		{
			$rv .= Swignition::Export::Contact::_AtomPerson(
				$triples,
				$authorSubject->uri,
				"\t<author>");
		}
		elsif ($author->type)
		{
			$rv .= "\t<author><url>".$author->toString."</url></author>\n";
		}
		else
		{
			$rv .= "\t<author><name>".$author->toString."</name></author>\n";
		}
	}

	my @contributors = allOfObj($S,
		'http://purl.invalid/stuff/atom/owl#contributor',
		'http://bblfish.net/work/atom-owl/2006-06-06/#contributor',
		'http://purl.org/dc/terms/contributor',
		'http://purl.org/dc/elements/1.1/contributor');
	foreach my $contributor (@contributors)
	{
		my $contributorSubject = findSubject($triples, $contributor);
		if ($contributorSubject && Swignition::Export::Contact::is($contributorSubject))
		{
			$rv .= Swignition::Export::Contact::_AtomPerson(
				$triples,
				$contributorSubject->uri,
				"\t<contributor>");
		}
		elsif ($contributor->type)
		{
			$rv .= "\t<contributor><url>".$contributor->toString."</url></contributor>\n";
		}
		else
		{
			$rv .= "\t<contributor><name>".$contributor->toString."</name></contributor>\n";
		}
	}

	$rv .= "\t<updated>UPDATED_PLACEHOLDER_99754106633f94d350db34d548d6091a</updated>\n";

	my @cats = allOfObj($S,
		'http://purl.invalid/stuff/atom/owl#category',
		'http://bblfish.net/work/atom-owl/2006-06-06/#category',
		'http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag');
	foreach my $cat (@cats)
	{
		my ($tag, $scheme, $label);
		my $catSubject = findSubject($triples, $cat->toString);
		
		if ($catSubject)
		{
			$tag = firstOf($catSubject,
				'http://purl.invalid/stuff/atom/owl#term',
				'http://bblfish.net/work/atom-owl/2006-06-06/#term',
				'http://www.holygoat.co.uk/owl/redwood/0.1/tags/name',
				'http://www.w3.org/1999/02/22-rdf-syntax-ns#value',
				'http://purl.org/dc/terms/title',
				'http://purl.org/dc/elements/1.1/title');
			$scheme = firstOf($catSubject,
				'http://purl.invalid/stuff/atom/owl#scheme',
				'http://bblfish.net/work/atom-owl/2006-06-06/#scheme');
			$label  = firstOf($catSubject,
				'http://purl.invalid/stuff/atom/owl#label',
				'http://bblfish.net/work/atom-owl/2006-06-06/#label',
				'http://www.w3.org/2000/01/rdf-schema#label',
				'http://www.holygoat.co.uk/owl/redwood/0.1/tags/name',
				'http://www.w3.org/1999/02/22-rdf-syntax-ns#value',
				'http://purl.org/dc/terms/title',
				'http://purl.org/dc/elements/1.1/title');
		}
		$tag   = $cat->toString if (!$tag);
		$label = $cat->toString if (!$label);
		
		$rv .= "\t<category term=\"".encode_entities_numeric($tag)."\" ";
		$rv .= "scheme=\"".encode_entities_numeric($scheme)."\" "
			if (length $scheme);
		$rv .= "label=\"".encode_entities_numeric($label)."\" "
			if (length $label);
		$rv .= "/>\n";
	}

	my $rights = firstOfLiteral($S,
		['http://purl.invalid/stuff/atom/owl#rights',
		'http://bblfish.net/work/atom-owl/2006-06-06/#rights',
		'http://purl.org/dc/terms/rights',
		'http://purl.org/dc/elements/1.1/rights',
		'http://purl.org/rss/1.0/modules/rss091#copyright'],
		['http://purl.invalid/stuff/atom/owl#xhtml',
		'http://bblfish.net/work/atom-owl/2006-06-06/#xhtml',
		'http://purl.invalid/stuff/atom/owl#html',
		'http://bblfish.net/work/atom-owl/2006-06-06/#html',
		'http://purl.invalid/stuff/atom/owl#text',
		'http://bblfish.net/work/atom-owl/2006-06-06/#text',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value']);
	$rv .= "\t<rights>".encode_entities_numeric($rights)."</rights>\n"
		if ($rights);
	
	my $updatedLatest;

	# RSS-style entries
	foreach my $sequence (allOf($S, 'http://purl.org/rss/1.0/items'))
	{
		my $Seq = findSubject($triples, $sequence);
		next unless (Swignition::Export::Entity::Collection::is($Seq, 1));
		
		my $n = 1;
		while ($n)
		{
			my $item = Swignition::Export::Entity::Collection::get_list_item($triples, $Seq->uri, $n);
			last if ($item->type 
				&& ($item->toString eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'));

			$rv .= Swignition::Export::BlogEntry::_outAtom($triples, $item->toString, $updatedLatest)
				if ($item->type);
			$n++;
		}
		
	}

	# AtomOWL-style entries
	foreach my $e (allOf($S,
		'http://purl.invalid/stuff/atom/owl#entry',
		'http://bblfish.net/work/atom-owl/2006-06-06/#entry'))
	{
		$rv .= Swignition::Export::BlogEntry::_outAtom($triples, $e, $updatedLatest);
	}
	
	my $updated = firstOf($S,
		'http://purl.invalid/stuff/atom/owl#updated',
		'http://bblfish.net/work/atom-owl/2006-06-06/#updated',
		'http://purl.org/dc/terms/modified',
		'http://purl.org/dc/terms/date',
		'http://purl.org/dc/elements/1.1/date',
		'http://www.w3.org/2002/12/cal/ical#dtstamp',
		'http://www.w3.org/2002/12/cal/ical#lastModified',
		'http://www.w3.org/2005/Atomupdated',
		'http://www.w3.org/2005/Atom#updated',
		'http://purl.org/rss/1.0/modules/rss091#pubDate',
		'http://purl.org/rss/1.0/modules/rss091#lastBuildDate');
	if (!$updated)
	{
		$updated = $updatedLatest;
		$updated = DateTime->now()
			if (!$updated);
	}
	if ($updated)
	{
		$updated = AtomDate($updated);
		$rv =~ s/UPDATED_PLACEHOLDER_99754106633f94d350db34d548d6091a/$updated/;
	}
	
	$rv .= "</feed>\n";
	return $rv;
}

1;
